﻿using System;
using System.Collections.Generic;
using System.Linq;
using BLToolkit.Data;
using BLToolkit.Data.Linq;
using BLToolkit.Reflection;
using Calendar.Logic.Core;
using Calendar.Logic.Log;
using Calendar.Logic.ObjectModel;

namespace Calendar.Logic.ObjectManager
{
    internal static class BaseManagerExtended
    {
        public static IQueryable<TE> Select<TE>(this IQueryable<TE> table, int? id)
            where TE : Entity
        {
            return table.Where(e => e.ID == id);
        }

        public static IQueryable<TE> SelectById<TE>(this IQueryable<TE> table, int? id)
            where TE : Entity
        {
            return table.Where(e => e.ID == id);
        }

        public static IQueryable<TE> SelectWithoutId<TE>(this IQueryable<TE> table, int? id)
            where TE : Entity
        {
            return table.Where(e => e.ID != id);
        }

        public static List<T> ToList<T>(this IQueryable<T> table, bool withoutException)
        {
            try
            {
                return table.ToList();

            }
            catch (Exception exc)
            {
                LogManager.Log(DsLogLevel.ERROR, "Получение результата запроса", exc.Message);
                if (withoutException) return new List<T>();
                throw;
            }
        }

        public static IQueryable<TJE> Select<TJE, TFE, TSE>(this Table<TJE> table, int fId, int sId)
            where TFE : Entity
            where TSE : Entity
            where TJE : JoinEntitys<TFE, TSE>
        {
            return table.Where(j => j.FRS_ID == fId && j.SCN_ID == sId);
        }

        public static IQueryable<TJE> SelectByFirst<TJE, TFE, TSE>(this Table<TJE> table, int fId)
            where TFE : Entity
            where TSE : Entity
            where TJE : JoinEntitys<TFE, TSE>
        {
            return table.Where(j => j.FRS_ID == fId);
        }

        public static IQueryable<TJE> SelectBySecond<TJE, TFE, TSE>(this Table<TJE> table, int sId)
            where TFE : Entity
            where TSE : Entity
            where TJE : JoinEntitys<TFE, TSE>
        {
            return table.Where(j => j.SCN_ID == sId);
        }

        public static IValueInsertable<TJE> Value<TJE>(this Table<TJE> table, int fId, int sId)
            where TJE : IJoinEntitys
        {
            return table.Value(j => j.FRS_ID, fId).Value(j => j.SCN_ID, sId);
        }
    }

    public class BaseManager<TM, TE>
        where TM : class, new()
        where TE : Entity
    {
        public static TM Instance = new TM();
        //{
        //    get{ return new TM(); }
        //}

        internal static Table<TE> Table //= GlobalContext.Instance.DataContext.GetTable<TE>();
        {
            get { return GlobalContext.Instance.DataContext.GetTable<TE>(); }
        }

        public List<TE> SelectAll()
        {
            return Table.ToList();
        }

        public TE SelectById(int id)
        {
            return Table.Select(id).FirstOrDefault();
        }

        internal int Insert(TE item)
        {
            var ret = (Int64)GlobalContext.Instance.DataContext.InsertWithIdentity(item);
            return (int)ret;
        }

        internal void InsertBatch(List<TE> items)
        {
            ((DbManager)GlobalContext.Instance.DataContext).InsertBatch(items);
        }

        internal void InsertWithoutIdentity(TE item)
        {
            GlobalContext.Instance.DataContext.Insert(item);
        }

        internal int Update(TE item)
        {
            return GlobalContext.Instance.DataContext.Update(item);
        }

        internal int DeleteByKey(int id)
        {
            return Table.Select(id).Delete();
        }

        public TE CreateInstance()
        {
            return TypeAccessor<TE>.CreateInstanceEx();
        }
    }

    public class BaseManager<TM, TJE, TFE, TSE>
        where TM : class, new()
        where TFE : Entity
        where TSE : Entity
        where TJE : JoinEntitys<TFE, TSE>
    {
        public static TM Instance = new TM();
        //{
        //    get { return new TM(); }
        //}

        internal static Table<TJE> Table //= GlobalContext.Instance.DataContext.GetTable<TJE>();
        {
            get { return GlobalContext.Instance.DataContext.GetTable<TJE>(); }
        }

        internal void InsertBatch(List<TJE> items)
        {
            ((DbManager)GlobalContext.Instance.DataContext).InsertBatch(items);
        }


        //internal int Insert(TJE item)
        //{
        //    var ret = GlobalContext.Instance.DataContext.Insert(item);
        //    return ret;
        //}
        internal void Insert(TJE item)
        {
            GlobalContext.Instance.DataContext.Insert(item);
        }

        internal void Update(TJE item)
        {
            GlobalContext.Instance.DataContext.Update(item);
        }


        internal void SetSecondsForFirst(int firstId, int[] secondsId)
        {
            var setSeconds = Table.SelectByFirst<TJE, TFE, TSE>(firstId).Select(j => j.SCN_ID).ToArray();

            foreach (var id in setSeconds.Where(id => !secondsId.Contains(id)))
            {
                var secondId = id;
                Table.Select<TJE, TFE, TSE>(firstId, secondId).Delete();
            }

            List<TJE> tmp  = secondsId.Where(id => !setSeconds.Contains(id)).Select(secondId => CreateInstance(firstId, secondId)).ToList();
            InsertBatch(tmp);
        }

        internal void SetFirstsForSecond(int secondId, int[] firstsId)
        {
            var setFirsts = Table.SelectBySecond<TJE, TFE, TSE>(secondId).Select(j => j.FRS_ID).ToArray();

            foreach (var id in setFirsts.Where(id => !firstsId.Contains(id)))
            {
                var firstId = id;
                Table.Select<TJE, TFE, TSE>(firstId, secondId).Delete();
            }

            List<TJE> tmp = firstsId.Where(id => !setFirsts.Contains(id)).Select(firstId => CreateInstance(firstId, secondId)).ToList();
            InsertBatch(tmp);
        }

        public TJE CreateInstance()
        {
            return TypeAccessor<TJE>.CreateInstanceEx();
        }

        public TJE CreateInstance(int firstId, int secondId)
        {
            TJE tmp = CreateInstance();
            tmp.FRS_ID = firstId;
            tmp.SCN_ID = secondId;
            return tmp;
        }
    }
}
